package org.fight.net.session;

import java.net.InetSocketAddress;
import java.util.Map;

import org.apache.commons.collections4.MapUtils;
import org.fight.actor.SessionActor;
import org.fight.cache.SessionCache;
import org.fight.net.EncryptionAndDecryptionUtil;
import org.fight.net.KcpConstant;

import com.sojoys.artifact.factory.session.ISession;
import com.sojoys.artifact.factory.session.ISessionFactory;
import com.sojoys.artifact.plugin.actor.ActorPlugin;
import com.sojoys.artifact.third.kcp.KCP;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.date.TimeInterval;

import akka.actor.Props;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramPacket;

public class KcpSessionFactory implements ISessionFactory<Map<String, Object>>{
	
	public ISession createSession(Map<String, Object> map){
		Channel channel = (Channel) map.get(KcpConstant.SOCKET_CHANNEL);
		InetSocketAddress address = (InetSocketAddress) map.get(KcpConstant.TARGET_ADDRESS);
		int conv = MapUtils.getIntValue(map, KcpConstant.CONV);
				
		ISession session = new KcpSession(channel);
		
		long nowTime = System.currentTimeMillis();
		// 会话标识
		session.setAttr(KcpConstant.CONV, conv);
		// 目标网络地址
		session.setAttr(KcpConstant.TARGET_ADDRESS, address);
		// 最后写数据时间
		session.setAttr(KcpConstant.LAST_WRITE_TIME, nowTime);
		// 最后读数据时间
		session.setAttr(KcpConstant.LAST_READ_TIME, nowTime);
		// BUFF
		session.setAttr(KcpConstant.BYTE_BUF, Unpooled.buffer());
		// 下一次更新时间
		session.setAttr(KcpConstant.NEXT_UPDATE_TIME,nowTime);
		// 是否需要更新
		session.setAttr(KcpConstant.NEED_UPDATE , true);
		// 解密钥匙
		session.setAttr(KcpConstant.DECRYPTION_KEYS , EncryptionAndDecryptionUtil.getDefaultCustomDecryptionKeys());
		// 加密钥密
		session.setAttr(KcpConstant.ENCRYPTION_KEYS , EncryptionAndDecryptionUtil.getDefaultCustomEncryptionKeys());
		// 创建actor
		session.setAttr(KcpConstant.ACTOR , ActorPlugin.getProxy().actorOf(Props.create(SessionActor.class,session)));
		// KCP
		session.setAttr(KcpConstant.KCP,new IKCP(conv, address, channel));
		// 加入缓存
		SessionCache.me().addCache(conv, session);
		
		return session;
	}
	
	
	class IKCP extends KCP{
		private InetSocketAddress address;
		private Channel channel;
		
		
		public IKCP(long conv_, InetSocketAddress address, Channel channel) {
			super(conv_);
			this.address = address;
			this.channel = channel;
			/**
			 *  nodelay ：是否启用 nodelay模式，0不启用；1启用。
				interval ：协议内部工作的 interval，单位毫秒，比如 10ms或者 20ms
				resend ：快速重传模式，默认0关闭，可以设置2（2次ACK跨越将会直接重传）
				nc ：是否关闭流控，默认是0代表不关闭，1代表关闭。
				普通模式： ikcp_nodelay(kcp, 0, 40, 0, 0);
				极速模式： ikcp_nodelay(kcp, 1, 10, 2, 1);
			 */
			this.NoDelay(1,10,2,1);
			this.WndSize(128, 128);
			this.SetMtu(470);
		}

		TimeInterval timer = DateUtil.timer();
		@Override
		protected void output(byte[] buffer, int size) {
			ByteBuf buf = Unpooled.directBuffer(size);
			buf.writeBytes(buffer, 0, size);
			DatagramPacket datagramPacket = new DatagramPacket(buf, address);
			// 发送
			channel.writeAndFlush(datagramPacket);
			System.out.println("send " + timer.interval());
			timer.restart();
		}
	}
}
